package self.zhangkang.chart.view.touch

import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.widget.OverScroller
import androidx.core.view.GestureDetectorCompat

/**
 * @author : Android-张康
 * created on: 2023/5/10 16:58
 * description: 触摸协助类
 *
 * @param context 上下文
 * @param view 当前的 View
 * @param onListener 监听
 * @param canScale 是否可以缩放
 */
class TouchHelper @JvmOverloads constructor(
    context: Context,
    private val view: View,
    private val onListener: OnListener,
    private val canScale: Boolean = true
) : GestureDetector.SimpleOnGestureListener(),
    ScaleGestureDetector.OnScaleGestureListener,
    GestureDetector.OnGestureListener {
    /**
     * 触摸监听
     */
    interface OnListener {

        /**
         * 缩放
         *
         * @param scaleFactor 缩放比率
         */
        fun onScale(scaleFactor: Float)

        /**
         * 滑动
         *
         * @param scrollX 本次滑动的 X
         */
        fun onScroll(scrollX: Float)

        /**
         * 轻点
         *
         * @param touchX 点击的 X 坐标
         * @param touchY 点击的 Y 坐标
         */
        fun onSingleTapUp(touchX: Float, touchY: Float)

        /**
         * 长按
         *
         * @param touchX 点击的 X 坐标
         * @param touchY 点击的 Y 坐标
         * @param isFinish 是否结束
         */
        fun onLongPress(touchX: Float, touchY: Float, isFinish: Boolean)

        /**
         * 获取蜡烛的宽度
         *
         * @return 返回当前蜡烛的宽度
         */
        fun getCandlestickWidth(): Float
    }


    private var mEnableGestureDetector = false

    /**
     * 缩放监听
     */
    private val mScaleDetector = ScaleGestureDetector(context, this)

    private val mGestureDetector = GestureDetectorCompat(context, this)

    private var mLastX: Float = 0.0F

    private var mScrollerLastX = 0

    private val mScroller = OverScroller(context)

    private var mInLongPress = false

    private var mLastLongPressY = 0.0F

    private var mInScale = false

    private val mHandler = Handler(Looper.getMainLooper())

    private val mFinishLongPressRunnable = createFinishLongPressRunnable()

    override fun onScale(detector: ScaleGestureDetector): Boolean {
        if (canScale) {
            onListener.onScale(detector.scaleFactor)
        }
        return true
    }

    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
        mInScale = true
        return true
    }

    override fun onScaleEnd(detector: ScaleGestureDetector) {
        mInScale = false
    }

    override fun onDown(e: MotionEvent): Boolean {
        mLastX = e.x
        closeLongPress()
        mScroller.forceFinished(true)
        return super.onDown(e)
    }

    override fun onScroll(
        downEvent: MotionEvent?,
        currentEvent: MotionEvent,
        distanceX: Float,
        distanceY: Float
    ): Boolean {
        downEvent ?: return false
        if (mScaleDetector.isInProgress) {
            return false
        }
        view.parent.requestDisallowInterceptTouchEvent(true)
        val lastDownX = mLastX
        val scrollX = lastDownX - currentEvent.x
        if (Math.abs(scrollX) < onListener.getCandlestickWidth()) {
            return true
        }
        mLastX = currentEvent.x
        onListener.onScroll(scrollX)
        return true
    }

    override fun onFling(
        e1: MotionEvent?,
        e2: MotionEvent,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        val startX = e2.x.toInt()
        val minX = onListener.getCandlestickWidth()
        mScrollerLastX = startX
        mScroller.fling(
            startX, 0, velocityX.toInt(), 0, minX.toInt(), Int.MAX_VALUE, 0, 0
        )
        return true
    }

    override fun onLongPress(e: MotionEvent) {
        if (mInScale) {
            return
        }
        mInLongPress = true
        mLastLongPressY = e.y
    }

    override fun onSingleTapUp(e: MotionEvent): Boolean {
        closeLongPress()
        onListener.onSingleTapUp(e.x, e.y)
        return true
    }

    fun onTouchEvent(event: MotionEvent?): Boolean {
        event ?: return false
        val result = mScaleDetector.onTouchEvent(event)
        when (event.action and MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_POINTER_DOWN -> {
                mEnableGestureDetector = true
                if (mInLongPress) {
                    view.parent.requestDisallowInterceptTouchEvent(true)
                    onListener.onLongPress(event.x, event.y, false)
                    mLastLongPressY = event.y
                }
            }

            MotionEvent.ACTION_MOVE -> {
                if (mInScale || mInLongPress) {
                    view.parent.requestDisallowInterceptTouchEvent(true)
                }
                if (mInLongPress) {
                    onListener.onLongPress(event.x, event.y, false)
                    mLastLongPressY = event.y
                }
            }

            MotionEvent.ACTION_UP -> {
                view.parent.requestDisallowInterceptTouchEvent(false)
                mEnableGestureDetector = false
                finishLongPress()
            }
        }
        return mEnableGestureDetector || mGestureDetector.onTouchEvent(event) || result
    }

    fun computeScrollOffset() {
        val computeScrollOffset = mScroller.computeScrollOffset()
        if (computeScrollOffset) {
            val currX = mScroller.currX
            onListener.onScroll(mScrollerLastX - currX * 1.0F)
            mScrollerLastX = currX
        }
    }

    fun forceFinished(finished: Boolean) {
        mScroller.forceFinished(finished)
    }

    fun onDetachedFromWindow() {
        mHandler.removeCallbacksAndMessages(null)
    }

    private fun finishLongPress() {
        mHandler.removeCallbacks(mFinishLongPressRunnable)
        if (mInLongPress) {
            mHandler.postDelayed(mFinishLongPressRunnable, 5000)
        }
    }

    private fun closeLongPress() {
        if (mInLongPress) {
            mHandler.removeCallbacks(mFinishLongPressRunnable)
            mFinishLongPressRunnable.run()
        }
    }

    private fun createFinishLongPressRunnable() = Runnable {
        onListener.onLongPress(-1F, -1F, true)
        mInLongPress = false
    }
}